package com.google.code.tretris.network;

import java.util.ArrayList;
import java.util.Collection;

import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;

import android.util.Log;

import com.google.code.tretris.common.WKC;
import com.google.code.tretris.events.MoveEvent;
import com.google.code.tretris.events.UpdateBoardEvent;
import com.google.code.tretris.network.connection.TretrisConnectionHandlerInterface;
import com.google.code.tretris.network.events.TretrisMessage;
import com.google.code.tretris.network.exceptions.ConnectionFailedException;
import com.google.code.tretris.network.exceptions.NotConnectedException;
import com.google.code.tretris.network.game.GameActionListener;
import com.google.code.tretris.network.game.GameNetworkInterface;
import com.google.code.tretris.network.peers.NetworkClient;

public class NetworkManager implements PacketListener, GameNetworkInterface {

	public static final String TAG = "TretrisNetworkManager";

	private Collection<NetworkClient> myRoster = new ArrayList<NetworkClient>();
	private Collection<NetworkClient> players = new ArrayList<NetworkClient>();
	boolean isConnected = false;

	private Collection<GameActionListener> rotationListeners = new ArrayList<GameActionListener>();
	private Collection<GameActionListener> moveListeners = new ArrayList<GameActionListener>();
	private Collection<GameActionListener> updateListeners = new ArrayList<GameActionListener>();

	private TretrisConnectionHandlerInterface conHandler;
	
	private static NetworkManager instance = null;
	
	protected NetworkManager(TretrisConnectionHandlerInterface connectionHandler) {
		this.conHandler = connectionHandler;	
	}
	
	public static NetworkManager newInstance(TretrisConnectionHandlerInterface connectionHandler) {
		if (instance == null) {
			instance = new NetworkManager(connectionHandler);	
		}		
		return instance;
	}
	
	public static NetworkManager getInstance() {
		if (instance == null) {
			throw new RuntimeException("Must be created via newInstance");
		}
		return instance;
	}	

	public void processPacket(Packet pack) {
		// Packet = Message = TretrisMessage
		Message packet = (Message) pack;

		// EVENT # user
		Log.d(TAG, "process packet...");
		if(packet.getBody().indexOf(TretrisMessage.MOVE_EVENT)!=-1) {
			// Move event
			for(GameActionListener lester : moveListeners) {
				String[] data0 = packet.getBody().split("#");				
				String[] data1= data0[1].split(",");
				int delta = Integer.parseInt(data1[0]);
				int rotation = Integer.parseInt(data1[1]);
				lester.move(new MoveEvent(packet.getFrom(), delta, rotation));
			}
		} 
		if(packet.getBody().indexOf(TretrisMessage.ROTATE_EVENT)!=-1) {
			// Rotate event
			for(GameActionListener lester : rotationListeners) {
				String[] data0 = packet.getBody().split("#");		
				String[] data1= data0[1].split(",");
				int delta = Integer.parseInt(data1[0]);
				int rotation = Integer.parseInt(data1[1]);
				lester.rotate(new MoveEvent(packet.getFrom(), delta, rotation));
			}
		}
		if(packet.getBody().indexOf(TretrisMessage.UPDATEBOARD_EVENT)!=-1) {
			
			// Update event
			for(GameActionListener lester : updateListeners) {				
				String data0 = packet.getBody().split("#")[1];
				// event # data/data/data
				String[] data = data0.split("/");								
				for(String split1 : data) {
					// user@user.user;0,0,0,0,0;asd 1
					String[] data2 = split1.split(";");												
					String username = data2[0];
					String[] boardData = data2[1].split(",");
					
					int[] blocks = new int[WKC.BOARD_WIDTH*WKC.BOARD_HEIGHT];
					
					for(int j = 0; j<blocks.length; j++) {
							blocks[j] = Integer.parseInt(boardData[j]);
					}
					
					String[] pieceData = data2[2].split(",");
					char pieceChar = pieceData[0].charAt(0);
					int x = Integer.parseInt(pieceData[1]);
					int y = Integer.parseInt(pieceData[2]);
					int rotation = Integer.parseInt(pieceData[3]);
										
					lester.update(new UpdateBoardEvent(username, x, y, rotation, pieceChar, blocks));	

				}
			}

		}
		
		if(((Message)pack).getBody().indexOf(TretrisMessage.CONTROLL_EVENT)!=-1) {
		
			// Populera en lista med alla spelare
			String[] first = ((Message)pack).getBody().split("#");
			String[] playerStrings = first[1].split(";");
			Collection<String> newPlayas = new ArrayList<String>();
			for(String player : playerStrings) {
				boolean isRegistered=false;
				for(NetworkClient client : this.players) {
					if(client.getClientID().equals(player)) isRegistered = true;
				}
				if(!isRegistered) newPlayas.add(player);
			}
			addPlayers(newPlayas);

			// En server skickar ett controllevent, vi är klient	
			for(NetworkClient c : players) {
				if(c.getClientID().equals(packet.getFrom())) this.server = c;
			}
			
		}
		
		//Log.i(TAG, pack.toXML());
	}


	private NetworkClient server = null;

	public void addPlayers(Collection<String> newPlayers) {
		for(NetworkClient e : myRoster) {
			if(newPlayers.contains(e.getClientID())&&
					!players.contains(e.getClientID())) {
				players.add(e);
			}
		}
	}

	public void addRotationListener(GameActionListener lester) {
		this.rotationListeners.add(lester);
	}

	public void removeRotationListener(GameActionListener lester) {
		this.rotationListeners.remove(lester);
	}

	public Collection<NetworkClient> getClients() {
		return players;
	}

	public void addMoveListener(GameActionListener mover) {
		this.moveListeners.add(mover);

	}

	public void removeMoveListener(GameActionListener mover) {
		this.moveListeners.remove(mover);

	}

	public void addUpdateListener(GameActionListener updater) {
		this.updateListeners.add(updater);

	}

	public void removeUpdateListener(GameActionListener updater) {
		this.updateListeners.remove(updater);

	}
	
	public void sendMovement(MoveEvent e) throws NotConnectedException {
		String message = TretrisMessage.MOVE_EVENT+"#";
		message = message + e.getDeltax() + "," +e.getRotationchange();
		conHandler.send(message, server.getClientID());
	}
	
	public void broadcastUpdate(Collection<UpdateBoardEvent> e) throws NotConnectedException {
		String message = TretrisMessage.UPDATEBOARD_EVENT+"#";
		for(UpdateBoardEvent event : e) {
			message = message + event.getClientID() + ";";
			int[] blocks = event.getBlocks() ;
			for(int n=0; n<blocks.length; n++) {
					message = message + blocks[n] + ",";
			}
			message = message.substring(0, message.length()-1);
			message = message + ";" + event.getTetromino() + "," 
							+ event.getX() + "," + event.getY() + "," 
							+ event.getRotation() + "/";
		}
		message = message.substring(0, message.length()-1);
		conHandler.broadcast(message, players);
		
	}

	public void broadcastControll() throws NotConnectedException {
		String message = "controlevent#";
		for (NetworkClient player : players) {
			message += player.getClientID();
			message += ";";			
		}
		message = message.substring(0, message.length() - 1);
		conHandler.broadcast(message, players);
	}
	
	public void connect(String user, String password) throws ConnectionFailedException {		
			this.myRoster = conHandler.connect(user, password, this);
			this.isConnected = true;
			players.add(new NetworkClient(user, user));
	}
	
	public void disconnect() throws NotConnectedException {
		this.conHandler.disconnect();
		this.isConnected = false;
	}

}
